package com.mate.cloud.hot;


import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

/**
 * 方案二：使用 Redisson 的分布式锁防止缓存击穿
 * @author:         MI
 * @email:          448341911@qq.com
 * @createTime:     2025/8/27 22:01
 * @updateUser:     MI
 * @updateTime:     2025/8/27 22:01
 * @updateRemark:   修改内容
 * @version:        1.0
 */
public class HotKeyWithLockService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 获取热点数据，防止缓存击穿
     */
    public Object getHotKeyWithLock(String key) {
        // 1. 先查Redis
        Object value = redisTemplate.opsForValue().get(key);
        if (value != null) {
            return value;
        }

        // 2. 获取分布式锁
        RLock lock = redissonClient.getLock("LOCK:" + key);
        try {
            // 尝试加锁，最多等待100ms，锁持有时间30秒
            if (lock.tryLock(100, 30000, TimeUnit.MILLISECONDS)) {
                try {
                    // 3. 再次检查缓存（双重检查锁）
                    value = redisTemplate.opsForValue().get(key);
                    if (value != null) {
                        return value;
                    }

                    // 4. 模拟从数据库加载数据
                    value = loadFromDB(key);

                    // 5. 写入Redis
                    if (value != null) {
                        redisTemplate.opsForValue().set(key, value, 1, TimeUnit.HOURS);
                    }

                    return value;
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        return null;
    }

    private Object loadFromDB(String key) {
        // 这里实现从数据库加载数据的逻辑
        // ...
        return "data_from_db";
    }
}
